	PAGE ,132 ;
	TITLE MSLPT - BIOS
	%OUT	...MSLPT.ASM

;==============================================================================
;REVISION HISTORY:
;AN000 - New for DOS Version 4.00 - J.K.
;AC000 - Changed for DOS Version 4.00 - J.K.
;AN00x - PTM number for DOS Version 4.00 - J.K.
;==============================================================================
;AN001 - P156 KBMLPT device driver's retry logic.                  8/18/87 J.K.
;==============================================================================
	itest=0
	INCLUDE MSGROUP.INC	;DEFINE CODE SEGMENT
	INCLUDE MSEQU.INC
	INCLUDE MSMACRO.INC
	INCLUDE DEVSYM.INC
	INCLUDE IOCTL.INC

	EXTRN BUS$EXIT:NEAR		;MSBIO1
	EXTRN ERR$CNT:NEAR		;MSBIO1
	EXTRN CMDERR:NEAR		;MSBIO1
	EXTRN GETDX:NEAR		;MSBIO1
	EXTRN EXIT:NEAR 		;MSBIO1
	EXTRN ERR$EXIT:NEAR		;MSBIO1
;DATA
	EXTRN PTRSAV:DWORD		;MSBIO1
	EXTRN TIMDEV:WORD		;MSCLOCK
	EXTRN LPT2DEV:WORD		;MSBIO2
	EXTRN WAIT_COUNT:WORD		;MSDATA
	EXTRN PRINTDEV:BYTE		;MSDATA
; IBM ROM STATUS BITS (I DON'T TRUST THEM, NEITHER SHOULD YOU)

NOTBUSYSTATUS	=   10000000B		; NOT BUSY
ACKSTATUS	=   01000000B		; ACKNOWLEDGE (FOR WHAT?)
NOPAPERSTATUS	=   00100000B		; NO MORE PAPER
SELECTEDSTATUS	=   00010000B		; THE PRINTER SAID IT WAS SELECTED
IOERRSTATUS	=   00001000B		; SOME KINDA ERROR
RESERVED	=   00000110B		; NOPS
TIMEOUTSTATUS	=   00000001B		; TIME OUT.


; WARNING!!!  THE IBM ROM DOES NOT RETURN JUST ONE BIT.  IT RETURNS A
; WHOLE SLEW OF BITS, ONLY ONE OF WHICH IS CORRECT.

;----------------------------------------------------------
;J.K. AN001; PRN$WRIT will retry only if error code is TIMEOUT.

;	WRITE TO PRINTER DEVICE

;   CX HAS COUNT OF BYTES
;   ES:DI POINT TO DESTINATION
;   AUXNUM HAS PRINTER NUMBER

	PUBLIC PRN$WRIT
PRN$WRIT PROC	NEAR
	ASSUME	DS:CODE 		; SET BY PRINTER DEVICE DRIVER ENTRY

	jcxz	Prn$Done		;No char to output
Prn$Loop:
	mov	bx, 2			;Initialize retry count
Prn$Out:
;SB34LPT000****************************************************************
;SB  Print the character at ES:[DI]
;SB	Call the function PrnOP to do this
;SB	The character to be printed goes in AL and the function code
;SB	for 'Output character' goes in AH
;SB	Check for error in printing.  
;SB	If there is no error go to print the next character.
;SB	If there is an error indicated see if it is due to TIMEOUT.  If the
;SB	error is not TIMEOUT then we can do nothing about it.  Just go to
;SB	print the next character.  If it is due to timeout we can execute
;SB     the code to retry the print which follows this piece of code
;SB		LOCS: 6

	mov	al,es:[di]	; assume AX disposible since enter
	xor	ah,ah		; via int 21h
	call	PrnOp		; print to printer
	jz	Prn$Con		; no error - continue
	test	ah,TIMEOUTSTATUS
	jz	Prn$Con		; NOT time out - continue

;SB34LPT000****************************************************************
	dec	bx			;Retry until count is exhausted.
	jnz	Prn$Out 		;Retry it.
	jmp short Pmessg		;Return with error.
   ;
   ; next character
   ;
Prn$Con:
	inc	di			;point to next char and continue
	loop	Prn$Loop
Prn$Done:
	jmp	Exit
Pmessg:
	jmp	Err$Cnt
PRN$WRIT	endp

;	 JCXZ	 EXVEC3 		 ; NO CHARS TO OUTPUT..
;PRN$LOOP:
;	 MOV	 BX,2			 ; INITIALIZE RETRY FLAG
;PRN$OUT:
;	 MOV	 AL,ES:[DI]		 ; GET CHAR INTO AL
;	 INC	 DI			 ; POINT TO NEXT CHAR
;	 XOR	 AH,AH			 ; AH=0 => OUTPUT CHAR IN DL
;	 CALL	 PRNOP			 ; TO INDICATE PRINT CHAR IN AL
;	 JNZ	 PRRETRY
;	 LOOP	 PRN$LOOP
;EXVEC3:
;	 JMP	 EXIT
;PRRETRY:
;	 DEC	 DI			 ; UNDO THE INC ABOVE...
;	 DEC	 BX
;	 JNZ	 PRN$OUT
;PMESSG:
;	 JMP	 ERR$CNT		 ;RETURN WITH THE ERROR
;PRN$WRIT ENDP

;--------------------------------------------------------

;	PRINTER STATUS ROUTINE

	PUBLIC PRN$STAT
PRN$STAT PROC	NEAR
	ASSUME	DS:CODE 		; SET BY PRINTER DEVICE DRIVER ENTRY

	CALL	PRNSTAT 		;DEVICE IN DX
	JNZ	PMESSG			; OTHER ERRORS WERE FOUND
;J.K. The next three lines are commented out, since it is a dead code.
;	 MOV	 AL,9			 ; AGAIN, ASSUME OUT OF PAPER...
;	 TEST	 AH,NOPAPERSTATUS
;	 JNZ	 PMESSG
	TEST	AH,NOTBUSYSTATUS
	jnz	Prn$Done		;No error. Exit
	JMP	BUS$EXIT
PRN$STAT ENDP

; TAKE THE APPROPRIATE PRINTER AND DO THE OPERATION.  TRIAGE THE STATUS
; RETURNED IN AH INTO SOME MEANINGFUL ERROR.

PRNSTAT PROC	NEAR
;SB33037**********************************************************************
	mov	AH, 2			; set command for get status  ;SB ;3.30*
PRNOP:								      ;SB ;3.30*
	call	GETDX			; determine which printer     ;SB ;3.30*
	int	17h			; call ROM-BIOS printer routine ;SB;3.30*

;SB33037**********************************************************************

; EXAMINE THE STATUS BITS TO SEE IF AN ERROR OCCURRED.	UNFORTUNATELY, SEVERAL
; OF THE BITS ARE SET SO WE HAVE TO PICK AND CHOOSE.  WE MUST BE EXTREMELY
; CAREFUL ABOUT BREAKING BASIC.

	TEST	AH,IOERRSTATUS		; I/O ERROR?
	JZ	CHECKNOTREADY		; NO, TRY NOT READY

; AT THIS POINT, WE KNOW WE HAVE AN ERROR.  THE CONVERSE IS NOT TRUE.

	MOV	AL,9			; FIRST, ASSUME OUT OF PAPER
	TEST	AH,NOPAPERSTATUS	; OUT OF PAPER SET?
	JNZ	RET1			; YES, ERROR IS SET
	INC	AL			; INDICATE I/O ERROR
RET1:

; WE HAVE TRIAGED NOW FOR OUT OF PAPER AND IO ERR (IGNORING TIME-OUT)

	RET				; RETURN WITH ERROR

; THE BITS SAID NO ERROR.  UNFORTUNATELY, THERE MAY BE OTHER THINGS AT WORK
; HERE.

CHECKNOTREADY:
	MOV	AL,2			; ASSUME NOT-READY
	TEST	AH,TIMEOUTSTATUS	; IS TIME-OUT SET?
					; IF NZ THEN ERROR, ELSE OK???
PRNOP2:
	RET
PRNSTAT ENDP

; OUTPUT UNTIL BUSY.  THIS ENTRY POINT IS USED EXCLUSIVELY BY THE PRINT
; SPOOLERS.  UNDER NO CURCUMSTANCES SHOULD THE DEVICE DRIVER BLOCK WAITING FOR
; THE DEVICE TO BECOME READY.

;   INPUTS:	CX HAS COUNT OF BYTES TO OUTPUT.
;		ES:DI POINTS TO SOURCE BUFFER
;   OUTPUTS:	SET THE NUMBER OF BYTES TRANSFERRED APPROPRIATELY
	PUBLIC	PRN$TILBUSY
PRN$TILBUSY PROC NEAR
	ASSUME	DS:CODE 		; SET BY PRINTER DEVICE DRIVER ENTRY

	PUSH	DS
	PUSH	ES
	POP	DS			; NOW ES AND DS BOTH POINT TO SOURCE BUFFER
	ASSUME	DS:NOTHING

	MOV	SI,DI			; EVERYTHING IS SET FOR LODSB
PRN$TILBLOOP:
	PUSH	CX
	PUSH	BX
	XOR	BX,BX
	MOV	BL,CS:[PRINTDEV]
	SHL	BX,1
	MOV	CX,CS:WAIT_COUNT[BX]	; WAIT COUNT TIMES TO COME READY
	POP	BX
PRN$GETSTAT:
	CALL	PRNSTAT 		; GET STATUS
	JNZ	PRN$BPERR		; ERROR
	TEST	AH,10000000B		; READY YET?
	LOOPZ	PRN$GETSTAT		; NO, GO FOR MORE
	POP	CX			; GET ORIGINAL COUNT
	JZ	PRN$BERR		; STILL NOT READY => DONE
	LODSB
	XOR	AH,AH
	CALL	PRNOP
	JNZ	PRN$BERR		; ERROR
	LOOP	PRN$TILBLOOP		; GO FOR MORE
PRN$B:
	POP	DS
	LDS	BX,CS:[PTRSAV]
	ASSUME	DS:NOTHING
	SUB	WORD PTR [BX].COUNT,CX	;# OF SUCCESSFUL I/O'S
	JMP	EXIT
PRN$TILBUSY ENDP

PRN$BPERR PROC	NEAR
	ASSUME	DS:CODE
	POP	CX
PRN$BERR:
	POP	DS
	LDS	BX,CS:[PTRSAV]
	ASSUME	DS:NOTHING

	SUB	WORD PTR [BX].COUNT,CX	;# OF SUCCESSFUL I/O'S
	JMP	ERR$EXIT
PRN$BPERR ENDP
;
; MANIPULATES THE VALUE IN WAIT_COUNT DEPENDING ON THE VALUE PASSED IN THE
; GENERIC IOCTL PACKET.
; IT EITHER SETS OR RETURNS THE CURRENT VALUE FOR THE RETRY COUNT FOR THE
; DEVICE.
;
	PUBLIC PRN$GENIOCTL
PRN$GENIOCTL PROC NEAR
	ASSUME	DS:CODE 		; SET BY PRINTER DEVICE DRIVER ENTRY

	LES	DI,[PTRSAV]
	CMP	ES:[DI].MAJORFUNCTION,IOC_PC
	JE	PRNFUNC_OK
PRNFUNCERR:
	JMP	CMDERR

PRNFUNC_OK:
	MOV	AL,ES:[DI].MINORFUNCTION
	LES	DI,ES:[DI].GENERICIOCTL_PACKET
	XOR	BX,BX
	MOV	BL,[PRINTDEV]		; GET INDEX INTO RETRY COUNTS
	SHL	BX,1
	MOV	CX,WAIT_COUNT[BX]	; PULL OUT RETRY COUNT FOR DEVICE
	CMP	AL,GET_RETRY_COUNT
	JZ	PRNGETCOUNT
	CMP	AL,SET_RETRY_COUNT
	JNZ	PRNFUNCERR
	MOV	CX,ES:[DI].RC_COUNT
PRNGETCOUNT:
	MOV	WAIT_COUNT[BX],CX	; PLACE "NEW" RETRY COUNT
	MOV	ES:[DI].RC_COUNT,CX	; RETURN CURRENT RETRY COUNT
	JMP	EXIT
PRN$GENIOCTL ENDP
CODE	ENDS
	END
